bitkeeper revision 1.1041.8.1 (40eac16as-X5mJEQ0g8YVoYYxLFmBg)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 6 Jul 2004 15:12:42 +0000 (15:12 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 6 Jul 2004 15:12:42 +0000 (15:12 +0000)
Tidy up and simplify the Python s-expression parser.

tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xend/XendRoot.py
tools/python/xen/xend/sxp.py
tools/python/xen/xm/main.py

index f14e6477c28c388e3e8d22e3ca787666ef55f1d2..1269c2155c3de3d5c94e1b579bba61ea2446739a 100644 (file)
@@ -291,6 +291,9 @@ def vm_restore(src, progress=0):
     if dom < 0:
         raise VmError('restore failed')
     vmconfig = sxp.from_string(d['vmconfig'])
+    if not vmconfig:
+        raise VmError('bad vmconfig s-expression')
+    vmconfig = vmconfig[0]
     vm.config = sxp.child_value(vmconfig, 'config')
     deferred = vm.dom_configure(dom)
     def vifs_cb(val, vm):
@@ -419,8 +422,8 @@ class XendDomainInfo:
         self.config = config
         try:
             self.name = sxp.child_value(config, 'name')
-            self.memory = int(sxp.child_value(config, 'memory', '128'))
-            if sxp.child(config, 'autorestart', None):
+            self.memory = int(sxp.child_value(config, 'memory') or '128')
+            if sxp.child(config, 'autorestart'):
                 self.autorestart = 1
             self.configure_backends()
             image = sxp.child_value(config, 'image')
@@ -449,7 +452,7 @@ class XendDomainInfo:
         """
         devices = []
         for d in sxp.children(self.config, 'device'):
-            dev = sxp.child0(d)
+            dev = sxp.child(d)
             if dev is None: continue
             if name == sxp.name(dev):
                 devices.append(dev)
@@ -580,7 +583,7 @@ class XendDomainInfo:
         if self.recreate: return
         memory = self.memory
         name = self.name
-        cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
+        cpu = int(sxp.child_value(self.config, 'cpu') or '-1')
         print 'init_domain>', memory, name, cpu
         dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
         if dom <= 0:
@@ -645,7 +648,7 @@ class XendDomainInfo:
         devices = sxp.children(self.config, 'device')
         index = {}
         for d in devices:
-            dev = sxp.child0(d)
+            dev = sxp.child(d)
             if dev is None:
                 raise VmError('invalid device')
             dev_name = sxp.name(dev)
@@ -664,7 +667,7 @@ class XendDomainInfo:
         """Set configuration flags if the vm is a backend for netif of blkif.
         """
         for c in sxp.children(self.config, 'backend'):
-            name = sxp.name(sxp.child0(c))
+            name = sxp.name(sxp.child(c))
             if name == 'blkif':
                 self.blkif_backend = 1
             elif name == 'netif':
@@ -742,7 +745,7 @@ def vm_image_linux(vm, image):
     """
     kernel = sxp.child_value(image, "kernel")
     cmdline = ""
-    ip = sxp.child_value(image, "ip", "dhcp")
+    ip = sxp.child_value(image, "ip") or "dhcp"
     if ip:
         cmdline += " ip=" + ip
     root = sxp.child_value(image, "root")
@@ -751,7 +754,7 @@ def vm_image_linux(vm, image):
     args = sxp.child_value(image, "args")
     if args:
         cmdline += " " + args
-    ramdisk = sxp.child_value(image, "ramdisk", '')
+    ramdisk = sxp.child_value(image, "ramdisk") or ''
     vifs = vm.config_devices("vif")
     vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs))
     return vm
@@ -768,7 +771,7 @@ def vm_image_netbsd(vm, image):
     #todo: Same as for linux. Is that right? If so can unify them.
     kernel = sxp.child_value(image, "kernel")
     cmdline = ""
-    ip = sxp.child_value(image, "ip", "dhcp")
+    ip = sxp.child_value(image, "ip") or "dhcp"
     if ip:
         cmdline += "ip=" + ip
     root = sxp.child_value(image, "root")
@@ -797,7 +800,7 @@ def vm_dev_vif(vm, val, index):
     defer = make_vif(vm.dom, vif, vmac, vm.recreate)
     def fn(id):
         dev = xend.netif_dev(vm.dom, vif)
-        devid = sxp.attribute(val, 'id')
+        devid = sxp.child_value(val, 'id')
         if devid:
             dev.setprop('id', devid)
         bridge = sxp.child_value(val, "bridge")
@@ -824,7 +827,7 @@ def vm_dev_vbd(vm, val, index):
     dev = sxp.child_value(val, 'dev')
     if not dev:
         raise VmError('vbd: Missing dev')
-    mode = sxp.child_value(val, 'mode', 'r')
+    mode = sxp.child_value(val, 'mode') or 'r'
     defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
     def fn(vbd):
         dev = xend.blkif_dev(vm.dom, vdev)
@@ -926,7 +929,7 @@ def vm_field_vnet(vm, config, val, index):
         if id is None:
             raise VmError('vnet: missing vif id')
         dev = vm.get_device_by_id('vif', id)
-        #vnet = sxp.child_value(v, 'vnet', 1)
+        #vnet = sxp.child_value(v, 'vnet') or '1'
         #mac = sxp.child_value(dev, 'mac')
         #vif = sxp.child_value(dev, 'vif')
         #vnet_bridge(vnet, mac, vm.dom, 0)
index 665f5df29ee2747f43170baa49618f6082f50e7b..3687f57f4a25a9e81143136e588c120a9720e0d3 100644 (file)
@@ -145,7 +145,7 @@ class XendRoot:
         val    default value (optional, defaults to None)
         returns value
         """
-        return sxp.child_value(self.config, name, val=val)
+        return sxp.child_value(self.config, name) or val
 
 def instance():
     global inst
index 143ba81ab41928095ee9e8c41d2b4e97914da82b..352f7f2933ea3add1ae2477914b3eab88915b2c9 100644 (file)
@@ -21,56 +21,19 @@ from StringIO import StringIO
 __all__ = [
     "mime_type", 
     "ParseError", 
-    "Parser", 
-    "atomp", 
-    "show", 
-    "show_xml", 
-    "elementp", 
+    "Parser",
+    "show",
     "name", 
-    "attributes", 
-    "attribute", 
     "children", 
     "child", 
-    "child_at", 
-    "child0", 
-    "child1", 
-    "child2", 
-    "child3", 
-    "child4", 
     "child_value",
-    "has_id", 
-    "with_id", 
-    "child_with_id", 
-    "elements", 
     "to_string",
     "from_string",
-    "all_from_string",
     "parse", 
     ]
 
 mime_type = "application/sxp"
 
-escapes = {
-    'a': '\a',
-    'b': '\b',
-    't': '\t',
-    'n': '\n',
-    'v': '\v',
-    'f': '\f',
-    'r': '\r',
-    '\\': '\\',
-    '\'': '\'',
-    '\"': '\"'}
-
-k_list_open  = "("
-k_list_close = ")"
-k_attr_open  = "@"
-k_eval       = "!"
-
-escapes_rev = {}
-for k in escapes:
-    escapes_rev[escapes[k]] = k
-
 class ParseError(StandardError):
 
     def __init__(self, parser, value):
@@ -86,7 +49,6 @@ class ParserState:
         self.parent = parent
         self.buf = ''
         self.val = []
-        self.delim = None
         self.fn = fn
 
     def push(self, fn):
@@ -95,28 +57,19 @@ class ParserState:
 class Parser:
 
     def __init__(self):
-        self.error = sys.stderr
         self.reset()
 
     def reset(self):
-        self.val = []
         self.eof = 0
-        self.err = 0
         self.line_no = 0
         self.char_no = 0
-        self.state = None
+        self.state = self.start_state = ParserState(self.state_start)
 
     def push_state(self, fn):
         self.state = self.state.push(fn)
 
     def pop_state(self):
-        val = self.state
         self.state = self.state.parent
-        if self.state and self.state.fn == self.state_start:
-            # Return to start state - produce the value.
-            self.val += self.state.val
-            self.state.val = []
-        return val
 
     def in_class(self, c, s):
         return s.find(c) >= 0
@@ -136,12 +89,6 @@ class Parser:
     def in_printable_class(self, c):
         return self.in_class(c, string.printable)
 
-    def set_error_stream(self, error):
-        self.error = error
-
-    def has_error(self):
-        return self.err > 0
-
     def at_eof(self):
         return self.eof
 
@@ -166,439 +113,131 @@ class Parser:
            self.char_no += 1 
 
         if self.state is None:
-            self.begin_start(None)
+            self.state = ParserState(self.state_start)
+
         self.state.fn(c)
 
     def ready(self):
-        return len(self.val) > 0
+        return len(self.start_state.val) > 0
 
     def get_val(self):
-        v = self.val[0]
-        self.val = self.val[1:]
+        v = self.start_state.val[0]
+        self.start_state.val = self.start_state.val[1:]
         return v
 
     def get_all(self):
-        return self.val
-
-    def begin_start(self, c):
-        self.state = ParserState(self.state_start)
+        return self.start_state.val
 
-    def end_start(self):
-        self.val += self.state.val
-        self.pop_state()
-    
     def state_start(self, c):
-        if self.at_eof():
-            self.end_start()
-        elif self.in_space_class(c):
+        if self.at_eof() or self.in_space_class(c):
             pass
         elif self.in_comment_class(c):
-            self.begin_comment(c)
-        elif c == k_list_open:
-            self.begin_list(c)
-        elif c == k_list_close:
+            self.push_state(self.state_comment)
+        elif c == '(':
+            self.push_state(self.state_list)
+        elif c == ')':
             raise ParseError(self, "syntax error: "+c)
         elif self.in_string_quote_class(c):
-            self.begin_string(c)
+            self.push_state(self.state_string)
+            self.state.buf = c
         elif self.in_printable_class(c):
-            self.begin_atom(c)
+            self.push_state(self.state_atom)
+            self.state.buf = c
         elif c == chr(4):
             # ctrl-D, EOT: end-of-text.
             self.input_eof()
         else:
             raise ParseError(self, "invalid character: code %d" % ord(c))
 
-    def begin_comment(self, c):
-        self.push_state(self.state_comment)
-        self.state.buf += c
-
-    def end_comment(self):
-        self.pop_state()
-    
     def state_comment(self, c):
         if c == '\n' or self.at_eof():
-            self.end_comment()
-        else:
-            self.state.buf += c
-
-    def begin_string(self, c):
-        self.push_state(self.state_string)
-        self.state.delim = c
+            self.pop_state()
 
-    def end_string(self):
-        val = self.state.buf
-        self.state.parent.val.append(val)
-        self.pop_state()
-        
     def state_string(self, c):
         if self.at_eof():
             raise ParseError(self, "unexpected EOF")
-        elif c == self.state.delim:
-            self.end_string()
-        elif c == '\\':
-            self.push_state(self.state_escape)
-        else:
-            self.state.buf += c
-
-    def state_escape(self, c):
-        if self.at_eof():
-            raise ParseError(self, "unexpected EOF")
-        d = escapes.get(c)
-        if d:
-            self.state.parent.buf += d
-            self.pop_state()
-        elif c == 'x':
-            self.state.fn = self.state_hex
-            self.state.val = 0
-        else:
-            self.state.fn = self.state_octal
-            self.state.val = 0
-            self.input_char(c)
-
-    def state_octal(self, c):
-        def octaldigit(c):
-            self.state.val *= 8
-            self.state.val += ord(c) - ord('0')
-            self.state.buf += c
-            if self.state.val < 0 or self.state.val > 0xff:
-                raise ParseError(self, "invalid octal escape: out of range " + self.state.buf)
-            if len(self.state.buf) == 3:
-               octaldone()
-               
-        def octaldone():
-            d = chr(self.state.val)
-            self.state.parent.buf += d
-            self.pop_state()
-            
-        if self.at_eof():
-            raise ParseError(self, "unexpected EOF")
-        elif '0' <= c <= '7':
-            octaldigit(c)
-        elif len(self.buf):
-            octaldone()
-            self.input_char(c)
-
-    def state_hex(self, c):
-        def hexdone():
-            d = chr(self.state.val)
-            self.state.parent.buf += d
+        self.state.buf += c
+        # Look out for non-escaped end delimiter
+        if self.state.buf[0] == c and self.state.buf[-2] != '\\':
+            try: # parse escape sequences but fall back to something simple
+                val = eval(compile(self.state.buf,'','eval'))
+            except:
+                val = self.state.buf[1:-1] # just strip the delimiters
+            self.state.parent.val.append(val)
             self.pop_state()
-            
-        def hexdigit(c, d):
-            self.state.val *= 16
-            self.state.val += ord(c) - ord(d)
-            self.state.buf += c
-            if self.state.val < 0 or self.state.val > 0xff:
-                raise ParseError(self, "invalid hex escape: out of range " + self.state.buf)
-            if len(self.state.buf) == 2:
-                hexdone()
-            
-        if self.at_eof():
-            raise ParseError(self, "unexpected EOF")
-        elif '0' <= c <= '9':
-            hexdigit(c, '0')
-        elif 'A' <= c <= 'F':
-            hexdigit(c, 'A')
-        elif 'a' <= c <= 'f':
-            hexdigit(c, 'a')
-        elif len(buf):
-            hexdone()
-            self.input_char(c)
-
-    def begin_atom(self, c):
-        self.push_state(self.state_atom)
-        self.state.buf = c
-
-    def end_atom(self):
-        val = self.state.buf
-        self.state.parent.val.append(val)
-        self.pop_state()
     
     def state_atom(self, c):
-        if self.at_eof():
-            self.end_atom()
-        elif (self.is_separator(c) or
-              self.in_space_class(c) or
-              self.in_comment_class(c)):
-            self.end_atom()
-            self.input_char(c)
+        if (self.at_eof() or
+            self.is_separator(c) or
+            self.in_space_class(c) or
+            self.in_comment_class(c)):
+            val = self.state.buf
+            self.state.parent.val.append(val)
+            self.pop_state()
+            if not self.at_eof():
+                self.input_char(c)
         else:
             self.state.buf += c
 
-    def begin_list(self, c):
-        self.push_state(self.state_list)
-
-    def end_list(self):
-        val = self.state.val
-        self.state.parent.val.append(val)
-        self.pop_state()
-
     def state_list(self, c):
         if self.at_eof():
             raise ParseError(self, "unexpected EOF")
-        elif c == k_list_close:
-            self.end_list()
+        elif c == ')':
+            val = self.state.val
+            self.state.parent.val.append(val)
+            self.pop_state()
         else:
             self.state_start(c)
 
-def atomp(sxpr):
-    """Check if an sxpr is an atom.
-    """
-    if sxpr.isalnum() or sxpr == '@':
-        return 1
-    for c in sxpr:
-        if c in string.whitespace: return 0
-        if c in '"\'\\(){}[]<>$#&%^': return 0
-        if c in string.ascii_letters: continue
-        if c in string.digits: continue
-        if c in '.-_:/~': continue
-        return 0
-    return 1
-    
 def show(sxpr, out=sys.stdout):
     """Print an sxpr in bracketed (lisp-style) syntax.
     """
     if isinstance(sxpr, types.ListType):
-        out.write(k_list_open)
-        i = 0
+        out.write('(')
         for x in sxpr:
-            if i: out.write(' ')
             show(x, out)
-            i += 1
-        out.write(k_list_close)
-    elif isinstance(sxpr, types.StringType) and atomp(sxpr):
-        out.write(sxpr)
+            out.write(' ')
+        out.write(')')
     else:
-        #out.write("'" + str(sxpr) + "'")
         out.write(repr(str(sxpr)))
 
-def show_xml(sxpr, out=sys.stdout):
-    """Print an sxpr in XML syntax.
-    """
-    if isinstance(sxpr, types.ListType):
-        element = name(sxpr)
-        out.write('<%s' % element)
-        for attr in attributes(sxpr):
-            out.write(' %s=%s' % (attr[0], attr[1]))
-        out.write('>')
-        i = 0
-        for x in children(sxpr):
-            if i: out.write(' ')
-            show_xml(x, out)
-            i += 1
-        out.write('</%s>' % element)
-    elif isinstance(sxpr, types.StringType) and atomp(sxpr):
-        out.write(sxpr)
-    else:
-        out.write(str(sxpr))
-
-def elementp(sxpr, elt=None):
-    """Check if an sxpr is an element of the given type.
-
-    sxpr sxpr
-    elt  element type
-    """
-    return (isinstance(sxpr, types.ListType)
-            and len(sxpr)
-            and (None == elt or sxpr[0] == elt))
-
 def name(sxpr):
-    """Get the element name of an sxpr.
-    If the sxpr is not an element (i.e. it's an atomic value) its name
-    is None.
-
-    sxpr
-
-    returns name (None if not an element).
+    """Get the element name of an sxpr, or None if a bad sxpr.
     """
-    val = None
     if isinstance(sxpr, types.StringType):
-        val = sxpr
-    elif isinstance(sxpr, types.ListType) and len(sxpr):
-        val = sxpr[0]
-    return val
-
-def attributes(sxpr):
-    """Get the attribute list of an sxpr.
-
-    sxpr
-
-    returns attribute list
-    """
-    val = []
-    if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
-        attr = sxpr[1]
-        if elementp(attr, k_attr_open):
-            val = attr[1:]
-    return val
-
-def attribute(sxpr, key, val=None):
-    """Get an attribute of an sxpr.
-
-    sxpr sxpr
-    key  attribute key
-    val  default value (default None)
-
-    returns attribute value
-    """
-    for x in attributes(sxpr):
-        if x[0] == key:
-            val = x[1]
-            break
-    return val
+        return sxpr
+    if isinstance(sxpr, types.ListType) and len(sxpr):
+        return sxpr[0]
+    return None
 
 def children(sxpr, elt=None):
-    """Get children of an sxpr.
-
-    sxpr sxpr
-    elt  optional element type to filter by
-
-    returns children (filtered by elt if specified)
+    """Get children of an s-expression @sxpr, optionally filtered by
+    element type @elt.
     """
-    val = []
-    if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
-        i = 1
-        x = sxpr[i]
-        if elementp(x, k_attr_open):
-            i += 1
-        val = sxpr[i : ]
+    if not isinstance(sxpr, types.ListType): return []
+    val = filter(lambda x: isinstance(x, types.ListType) and len(x) > 0, sxpr)
     if elt:
-        def iselt(x):
-            return elementp(x, elt)
-        val = filter(iselt, val)
-    return val
-
-def child(sxpr, elt, val=None):
-    """Get the first child of the given element type.
-
-    sxpr sxpr
-    elt  element type
-    val  default value
-    """
-    for x in children(sxpr):
-        if elementp(x, elt):
-            val = x
-            break
-    return val
-
-def child_at(sxpr, index, val=None):
-    """Get the child at the given index (zero-based).
-
-    sxpr  sxpr
-    index index
-    val   default value
-    """
-    kids = children(sxpr)
-    if len(kids) > index:
-        val = kids[index]
-    return val
-
-def child0(sxpr, val=None):
-    """Get the zeroth child.
-    """
-    return child_at(sxpr, 0, val)
-
-def child1(sxpr, val=None):
-    """Get the first child.
-    """
-    return child_at(sxpr, 1, val)
-
-def child2(sxpr, val=None):
-    """Get the second child.
-    """
-    return child_at(sxpr, 2, val)
-
-def child3(sxpr, val=None):
-    """Get the third child.
-    """
-    return child_at(sxpr, 3, val)
-
-def child4(sxpr, val=None):
-    """Get the fourth child.
-    """
-    return child_at(sxpr, 4, val)
-
-def child_value(sxpr, elt, val=None):
-    """Get the value of the first child of the given element type.
-    Assumes the child has an atomic value.
-
-    sxpr sxpr
-    elt  element type
-    val  default value
-    """
-    kid = child(sxpr, elt)
-    if kid:
-        val = child_at(kid, 0, val)
+        val = filter(lambda x,y=elt: x[0] == y, val)
     return val
 
-def has_id(sxpr, id):
-    """Test if an s-expression has a given id.
+def child(sxpr, elt=None, idx=0):
+    """Get the @idx'th child of the optional filtering type @elt in @sxpr.
     """
-    return attribute(sxpr, 'id') == id
-
-def with_id(sxpr, id, val=None):
-    """Find the first s-expression with a given id, at any depth.
-
-    sxpr   s-exp or list
-    id     id
-    val    value if not found (default None)
+    x = children(sxpr, elt)
+    if len(x) > idx:
+        return x[idx]
+    return None
 
-    return s-exp or val
+def child_value(sxpr, elt=None):
+    """Get the value of the first child of @sxpr with the optional type @elt.
     """
-    if isinstance(sxpr, types.ListType):
-        for n in sxpr:
-            if has_id(n, id):
-                val = n
-                break
-            v = with_id(n, id)
-            if v is None: continue
-            val = v
-            break
-    return val
-
-def child_with_id(sxpr, id, val=None):
-    """Find the first child with a given id.
-
-    sxpr   s-exp or list
-    id     id
-    val    value if not found (default None)
-
-    return s-exp or val
-    """
-    if isinstance(sxpr, types.ListType):
-        for n in sxpr:
-            if has_id(n, id):
-                val = n
-                break
-    return val
-
-def elements(sxpr, ctxt=None):
-    """Generate elements (at any depth).
-    Visit elements in pre-order.
-    Values generated are (node, context)
-    The context is None if there is no parent, otherwise
-    (index, parent, context) where index is the node's index w.r.t its parent,
-    and context is the parent's context.
-
-    sxpr   s-exp
-
-    returns generator
-    """
-    yield (sxpr, ctxt)
-    i = 0
-    for n in children(sxpr):
-        if isinstance(n, types.ListType):
-            # Calling elements() recursively does not generate recursively,
-            # it just returns a generator object. So we must iterate over it.
-            for v in elements(n, (i, sxpr, ctxt)):
-                yield v
-        i += 1
+    x = child(sxpr, elt)
+    if not isinstance(x, types.ListType) or len(x) < 2:
+        return None
+    return x[1]
 
 def to_string(sxpr):
-    """Convert an sxpr to a string.
-
-    sxpr sxpr
-    returns string
+    """Convert an s-expression @sxpr to a string.
     """
     io = StringIO()
     show(sxpr, io)
@@ -608,35 +247,14 @@ def to_string(sxpr):
     return val
 
 def from_string(str):
-    """Create an sxpr by parsing a string.
-
-    str string
-    returns sxpr
-    """
-    io = StringIO(str)
-    vals = parse(io)
-    if vals is []:
-        return None
-    else:
-        return vals[0]
-    
-
-def all_from_string(str):
-    """Create an sxpr list by parsing a string.
-
-    str string
-    returns sxpr list
+    """Create an sxpr list from a given input string @str.
     """
     io = StringIO(str)
     vals = parse(io)
     return vals
 
 def parse(io):
-    """Completely parse all input from 'io'.
-
-    io input file object
-    returns list of values, None if incomplete
-    raises ParseError on parse error
+    """Completely parse all input from file @io.
     """
     pin = Parser()
     while 1:
@@ -649,19 +267,11 @@ def parse(io):
     else:
         val = None
     return val
-   
 
+   
 if __name__ == '__main__':
-    print ">main"
     pin = Parser()
-    while 1:
-        buf = sys.stdin.read(1024)
-        #buf = sys.stdin.readline()
-        pin.input(buf)
-        while pin.ready():
-            val = pin.get_val()
-            print
-            print '****** val=', val
-        if len(buf) == 0:
-            break
-
+    buf = sys.stdin.read(1024)
+    pin.input(buf)
+    while pin.ready():
+        print '\n****** val=', pin.get_val()
index 97a36f6711db871ab91940ce01408e5622ce141c..9ae1fb67b8cdda28348fc59d4c11e5322b20bd63 100644 (file)
@@ -246,11 +246,11 @@ class ProgList(Prog):
             info = server.xend_domain(dom)
             d = {}
             d['dom'] = int(dom)
-            d['name'] = sxp.child_value(info, 'name', '??')
-            d['mem'] = int(sxp.child_value(info, 'memory', '0'))
-            d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
-            d['state'] = sxp.child_value(info, 'state', '??')
-            d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
+            d['name'] = sxp.child_value(info, 'name') or '??'
+            d['mem'] = int(sxp.child_value(info, 'memory') or '-1')
+            d['cpu'] = int(sxp.child_value(info, 'cpu') or '-1')
+            d['state'] = sxp.child_value(info, 'state') or '??'
+            d['cpu_time'] = float(sxp.child_value(info, 'cpu_time') or '-1')
             print ("%(dom)-4d %(name)-16s %(mem)7d  %(cpu)3d  %(state)5s  %(cpu_time)7.1f" % d)
 
     def long_list(self, doms):
@@ -424,9 +424,9 @@ class ProgConsoles(Prog):
         for x in l:
             info = server.xend_console(x)
             d = {}
-            d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1]
-            d['port'] = sxp.child_value(info, 'port', '?')
-            d['id'] = sxp.child_value(info, 'id', '?')
+            d['dom'] = (sxp.child(info, 'dst') or ['dst', '?', '?'])[1]
+            d['port'] = sxp.child_value(info, 'port') or '?'
+            d['id'] = sxp.child_value(info, 'id') or '?'
             print "%(dom)3s %(port)4s %(id)3s" % d
 
 xm.prog(ProgConsoles)